package org.xxpay.pay.channel.guanghui;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.xxpay.common.bean.result.PayException;
import org.xxpay.common.exception.PayErrorException;
import org.xxpay.common.http.HttpRequestTemplate;
import org.xxpay.common.util.DateUtils;
import org.xxpay.common.util.str.StringUtils;
import org.xxpay.core.common.constant.PayConstant;
import org.xxpay.core.common.util.MyLog;
import org.xxpay.core.entity.PayOrder;
import org.xxpay.pay.channel.BasePayment;
import org.xxpay.pay.channel.gepay.GepayPaymentService;
import org.xxpay.pay.channel.guanghui.utils.GfhB2CBank;
import org.xxpay.pay.channel.guanghui.utils.GhSignUtils;
import org.xxpay.pay.mq.BaseNotify4MchPay;

import java.util.Date;
import java.util.Map;
import java.util.TreeMap;

@Service
public class GhpayPaymentService extends BasePayment {

    private final static String logPrefix = "【广汇付】";

    public static final String REQ_PAY = "/trade/invoke";//支付下单后缀

    public static final String REQ_QUERY = "/query/invoke";//订单查询


    @Autowired
    public BaseNotify4MchPay baseNotify4MchPay;

    private static final MyLog _log = MyLog.getLog(GepayPaymentService.class);

    @Override
    public String getChannelName() {
        return GhpayConfig.CHANNEL_NAME;
    }

    /**
     * 查询订单
     * @param payOrder
     * @return
     */
    @Override
    public JSONObject query(PayOrder payOrder) {
        JSONObject retObj = buildRetObj();
        GhpayConfig config = new GhpayConfig(getPayParam(payOrder));
        Map<String,Object> params = setQueryParams(payOrder,config);

        _log.info("{}请求参数：{}", logPrefix, params.toString());

        HttpRequestTemplate requestTemplate = new HttpRequestTemplate(null);
        JSONObject  result = requestTemplate.postForObject(getReqUrl(config.getRequestUrl(),REQ_QUERY), params, JSONObject.class);

        _log.info("{}查单同步请求响应参数：{}", logPrefix, result.toJSONString());

        if (result.getString("plat_order_sn").equals(payOrder.getPayOrderId())){
            if (result.getString("payment_status").equals("1")){
                retObj.put("status", 2);    // 支付中
                retObj.put(PayConstant.RETURN_PARAM_RETCODE, PayConstant.RETURN_VALUE_SUCCESS);
                retObj.put("channelOrderNo", result.getString("order_id"));
                retObj.put("channelObj", result);
                return retObj;
            }
        }

        retObj.put(PayConstant.RETURN_PARAM_RETCODE, PayConstant.RETURN_VALUE_FAIL);
        retObj.put(PayConstant.RESULT_PARAM_ERRDES, "支付状态：" +result.getString("payment_status") + "0-待支付 1-已支付 2-已取消 3-支付失败 4-下单失败 5-处理中");
        return retObj;
    }

    /**
     * 支付下单
     * @param payOrder
     * @return
     */
    @Override
    public JSONObject pay(PayOrder payOrder){
        String channelId = payOrder.getChannelId();
        JSONObject retObj;
        switch (channelId) {
            case GhpayConfig.CHANNEL_NAME_JD_QR:
                retObj = doOrderReq(payOrder);
                break;
            case GhpayConfig.CHANNEL_NAME_UNION:
                retObj = doOrderReq(payOrder);
                break;
            case GhpayConfig.CHANNEL_NAME_WX_QR:
                retObj = doOrderReq(payOrder);
                break;
            case GhpayConfig.CHANNEL_NAME_ALI_QR:
                retObj = doOrderReq(payOrder);
                break;
            case GhpayConfig.CHANNEL_NAME_B2C:
                retObj = doB2cOrderReq(payOrder);
                break;
            case GhpayConfig.CHANNEL_NAME_QUICK_WAP:
                retObj = doQuickOrderReq(payOrder);
                break;
            default:
                retObj = buildRetObj(PayConstant.RETURN_VALUE_FAIL, "不支持的渠道[channelId="+channelId+"]");
                break;
        }
        return retObj;
    }

    //网关下单实现
    private JSONObject doB2cOrderReq(PayOrder payOrder){
        GhpayConfig config = new GhpayConfig(getPayParam(payOrder));
        // 请求参数
        Map<String,Object> params = setParams(payOrder,config,"B2C");

        _log.info("{}请求数据:{}", getChannelName(), JSON.toJSONString(params));
        // 将订单改为支付中
        rpcCommonService.rpcPayOrderService.updateStatus4Ing(payOrder.getPayOrderId(), null);
        HttpRequestTemplate requestTemplate = new HttpRequestTemplate(null);
        JSONObject  result = requestTemplate.postForObject(getReqUrl(config.getRequestUrl(),REQ_PAY), params, JSONObject.class);

        _log.info("{}响应参数：{}", logPrefix, result);

        JSONObject retObj = new JSONObject();
        String url = null;
        if (result.getString("respCode").equals(GhpayConfig.RESPONSE_RESULT_OK)){
            String res = result.getString("result");
            String qrtype = result.getJSONObject("result").getString("qrtype");
            if(qrtype.equals("1")){
                String reurl = result.getJSONObject("result").getString("url");
                return buildPayResultOfCodeURL(retObj, payOrder, reurl);
            }
            if (StringUtils.isNotEmpty(res)){
                String reurl = result.getJSONObject("result").getString("url");
                retObj.put("payOrderId", payOrder.getPayOrderId());
                JSONObject payInfo = new JSONObject();
                payInfo.put("codeUrl",qrtype);
                payInfo.put("payImageUrl",reurl);
                payInfo.put("payMethod",PayConstant.PAY_METHOD_CODE_IMG);
                retObj.put("payParams", payInfo);
                retObj.put(PayConstant.RETURN_PARAM_RETCODE, PayConstant.RETURN_VALUE_SUCCESS);
                return retObj;
            }
        }
        throw  new PayErrorException(new PayException("Invalid Arguments", "广汇付下单失败"));
    }

    //快捷下单实现
    private JSONObject doQuickOrderReq(PayOrder payOrder){
        GhpayConfig config = new GhpayConfig(getPayParam(payOrder));
        // 请求参数
        Map<String,Object> params = setParams(payOrder,config,"QUICK");

        _log.info("{}请求数据:{}", getChannelName(), JSON.toJSONString(params));
        // 将订单改为支付中
        rpcCommonService.rpcPayOrderService.updateStatus4Ing(payOrder.getPayOrderId(), null);
        HttpRequestTemplate requestTemplate = new HttpRequestTemplate(null);
        JSONObject  result = requestTemplate.postForObject(getReqUrl(config.getRequestUrl(),REQ_PAY), params, JSONObject.class);

        _log.info("{}响应参数：{}", logPrefix, result);

        JSONObject retObj = new JSONObject();
        String url = null;
        if (result.getString("respCode").equals(GhpayConfig.RESPONSE_RESULT_OK)){
            String res = result.getString("result");
            String qrtype = result.getJSONObject("result").getString("ishtml");
            if(qrtype.equals("0")){
                if (StringUtils.isNotEmpty(res)){
                    String reurl = result.getJSONObject("result").getString("url");
                    return buildPayResultOfForm(retObj, payOrder,getHtml( reurl));
                }
                throw  new PayErrorException(new PayException("Invalid Arguments", "广汇付下单失败"));
            }
            throw  new PayErrorException(new PayException("Invalid Arguments", "广汇付下单失败"));
        }
        throw  new PayErrorException(new PayException("Invalid Arguments", "广汇付下单失败"));
    }


    //下单实现
    private JSONObject doOrderReq(PayOrder payOrder){
        GhpayConfig config = new GhpayConfig(getPayParam(payOrder));
        // 请求参数
        Map<String,Object> params = setParams(payOrder,config,"CODEIMAGE");

        _log.info("{}请求数据:{}", getChannelName(), JSON.toJSONString(params));
        // 将订单改为支付中
        rpcCommonService.rpcPayOrderService.updateStatus4Ing(payOrder.getPayOrderId(), null);
        HttpRequestTemplate requestTemplate = new HttpRequestTemplate(null);
        JSONObject  result = requestTemplate.postForObject(getReqUrl(config.getRequestUrl(),REQ_PAY), params, JSONObject.class);

        _log.info("{}响应参数：{}", logPrefix, result);

        JSONObject retObj = new JSONObject();
        String url = null;
        if (result.getString("respCode").equals(GhpayConfig.RESPONSE_RESULT_OK)){
                String res = result.getString("result");
                String qrtype = result.getJSONObject("result").getString("qrtype");
                if(qrtype.equals("2")){
                    String reurl = result.getJSONObject("result").getString("url");
                    return buildPayResultOfForm(retObj, payOrder,getHtml( reurl));
                }
                if (StringUtils.isNotEmpty(res)){
                    String reurl = result.getJSONObject("result").getString("url");
                    retObj.put("payOrderId", payOrder.getPayOrderId());
                    JSONObject payInfo = new JSONObject();
                    payInfo.put("codeUrl",qrtype);
                    payInfo.put("payImageUrl",reurl);
                    payInfo.put("payMethod",PayConstant.PAY_METHOD_CODE_IMG);
                    retObj.put("payParams", payInfo);
                    retObj.put(PayConstant.RETURN_PARAM_RETCODE, PayConstant.RETURN_VALUE_SUCCESS);
                    return retObj;
                }
        }
         throw  new PayErrorException(new PayException("Invalid Arguments", "广汇付下单失败"));
    }

    //设置下单请求参数
    private  Map<String, Object> setParams(PayOrder payOrder, GhpayConfig config ,String payType){
        Map<String,Object> data = new TreeMap();
        data.put("requestId",payOrder.getPayOrderId());//请求唯一订单号
        data.put("orgId",config.getAppId());//机构号
        data.put("timestamp", DateUtils.YYYYMMDDHHMMSS.format(new Date()));
        data.put("productId",config.getPayProduct());//产品Id
        data.put("dataSignType","1");//上送的业务参数是否加密，为空默认为明文传输 0-不加密，明文传输 1-DES加密，密文传输
        String businessData = null;
        switch (payType) {
            case "B2C":
                businessData = getB2CBusinessData(payOrder);
                break;
            case "QUICK":
                businessData = getQuickWapBusinessData(payOrder);
                break;
            case "CODEIMAGE":
                businessData = getBusinessData(payOrder);
                break;
            default:
                businessData = getBusinessData(payOrder);
                break;
        }
        data.put("businessData",businessData);//对应产品交互业务数据
        data.put("signData",GhSignUtils.setSign(data,config));
        _log.info("广汇付请求报文：{}", JSONObject.toJSONString(data));
        return data;
    }

    /**
     * 获取B2C请求业务数据
     * @param payOrder
     * @return
     */
    private String getB2CBusinessData(PayOrder payOrder) {
        GhpayConfig config = new GhpayConfig(getPayParam(payOrder));
        Map<String, Object> busMap = Maps.newHashMap();
        busMap.put("merno",config.getMchId()); //商户号

        busMap.put("amount", payOrder.getAmount());//交易金额
        busMap.put("bus_no", "0499"); //业务编号,固定0499
        busMap.put("goods_info", "饮水机");//支付商品信息
        busMap.put("order_id", payOrder.getPayOrderId());//支付商品信息
        String bankCode =  JSONObject.parseObject(payOrder.getExtra()).getString("bankCode");
        busMap.put("cardname", GfhB2CBank.valueOf(bankCode).getName());//银行名称，参考银行卡支持列表
        busMap.put("bank_code", GfhB2CBank.valueOf(bankCode).getCode());//银行名称，参考银行卡支持列表
        busMap.put("return_url",payOrder.getReturnUrl());//通知地址
        busMap.put("notify_url", payConfig.getNotifyUrl(getChannelName()));//通知地址
        busMap.put("card_type", 1);//卡类型 1-储蓄卡 2-信用卡,仅支持储蓄卡
        busMap.put("channelid", 1);//账户类型 1-对私 2-对公,仅支持对私


        return GhSignUtils.getEncryptionDate(busMap,config);
    }

    /**
     * 获取B2C请求业务数据
     * @param payOrder
     * @return
     */
    private String getQuickWapBusinessData(PayOrder payOrder) {
        GhpayConfig config = new GhpayConfig(getPayParam(payOrder));
        Map<String, Object> busMap = Maps.newHashMap();
        busMap.put("merno",config.getMchId()); //商户号
        busMap.put("bus_no", "0399"); //业务编号,固定0399
        busMap.put("amount", payOrder.getAmount());//交易金额
        busMap.put("goods_info", "饮水机");//支付商品信息
        busMap.put("order_id", payOrder.getPayOrderId());//支付商品信息

        busMap.put("return_url",payOrder.getReturnUrl());//通知地址
        busMap.put("notify_url", payConfig.getNotifyUrl(getChannelName()));//通知地址



        return GhSignUtils.getEncryptionDate(busMap,config);
    }

    /**
     * 获取二维码请求业务数据
     * @param payOrder
     * @return
     */
    private String getBusinessData(PayOrder payOrder) {
        GhpayConfig config = new GhpayConfig(getPayParam(payOrder));
        Map<String, Object> busMap = Maps.newHashMap();
        busMap.put("merno",config.getMchId()); //商户号
        busMap.put("order_id", payOrder.getPayOrderId()); //订单编号
        busMap.put("notify_url", payConfig.getNotifyUrl(getChannelName()));//通知地址
        busMap.put("return_url",payOrder.getReturnUrl());//通知地址
        busMap.put("bus_no", config.getPayMode());//bus_no
        busMap.put("amount", payOrder.getAmount());
        busMap.put("goods_info", "饮水机");
        return GhSignUtils.getEncryptionDate(busMap,config);
    }

    /**
     * 设置查单请求参数
     * @param payOrder
     * @param config
     * @return
     */
    private  Map<String, Object> setQueryParams(PayOrder payOrder, GhpayConfig config){
        Map<String,Object> data = new TreeMap();
        data.put("requestId",payOrder.getPayOrderId());//请求唯一订单号
        data.put("orgId",config.getAppId());//机构号
        data.put("timestamp", DateUtils.YYYYMMDDHHMMSS.format(new Date()));
        data.put("productId","9701");//产品Id
        data.put("dataSignType","1");//上送的业务参数是否加密，为空默认为明文传输 0-不加密，明文传输 1-DES加密，密文传输
        data.put("businessData",getBusinessQueryData(payOrder));//对应产品交互业务数据
        data.put("signData",GhSignUtils.setSign(data,config));
        _log.info("广汇付请求报文：{}", JSONObject.toJSONString(data));
        return data;
    }

    /**
     * 设置查单请求业务参数
     * @param payOrder
     * @return
     */
    private String getBusinessQueryData(PayOrder payOrder) {
        GhpayConfig config = new GhpayConfig(getPayParam(payOrder));
        Map<String, Object> busMap = Maps.newHashMap();
        busMap.put("merno",config.getMchId()); //商户号
        busMap.put("order_id", payOrder.getPayOrderId()); //订单编号
        return GhSignUtils.getEncryptionDate(busMap,config);
    }

    //获取请求html
    private String getHtml(String payUrl){
        StringBuffer buffer = new StringBuffer();
        buffer.append("<script type=\"text/javascript\">");
        buffer.append("window.location.href=\""+payUrl+"\"");
        buffer.append("</script>");
        return buffer.toString();
    }

}
